﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using P2PChat.Data;
using System.Xml.Linq;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net.Sockets;

namespace P2PChat.Server
{
    public static class NetAccesser
    {
        public static NetPacket AccessSearchFriend(Data.Packets.SearchFriendPacket searchFriendPacket)
        {
            DBCDataContext dbc = new DBCDataContext();
            XElement searchResult = new XElement("SearchResult");
            try {
                // 首先通过电子邮件地址判断对象
                if (searchFriendPacket.SearchText_Email != null)
                {
                    if (dbc.tb_Users.Count(x => x.regEmail == searchFriendPacket.SearchText_Email) > 0)
                    {
                        searchResult.Add(dbc.tb_Users.First(x => x.regEmail == searchFriendPacket.SearchText_Email).personInfo);
                    }
                }
                if (searchFriendPacket.SearchText_Nickname != null)
                {
                    XElement[] elems = dbc.tb_Users.Select(x => x.personInfo).ToArray();
                    if (elems.Where(x => x.Element("Nickname") != null).Count(
                        x => x.Element("Nickname").Value.Contains(searchFriendPacket.SearchText_Nickname)) > 0)
                    {
                        searchResult.Add(
                            elems.Where(x => x.Element("Nickname") != null).Where(
                            x => x.Element("Nickname").Value.Contains(searchFriendPacket.SearchText_Nickname)));
                    }
                }
                return new NetPacket() {
                    Tag = PacketTag.SearchFriend,
                    Content = new P2PChat.Data.Packets.SearchFriendResultPacket() {
                        ResultXml = searchResult,
                    },
                };
            } 
            catch (Exception ex) 
            {
                if (iLog != null) {
                    iLog.Add(@"在处理好友搜索的过程中出现异常 : " + ex.Message);
                }
                throw ex;
            }
        }

        public static NetPacket AccessApplyPersonalInfo(Data.Packets.ApplyPersonalInfoPacket applyPersonalInfoPacket)
        {
            DBCDataContext dbc = new DBCDataContext();
            try
            {
                // 将数据库中对应的数据更新为新的XML
                dbc.tb_Users.First(x => x.guid == Guid.Parse(
                    applyPersonalInfoPacket.NewPersonalInfo.Attribute("GUID").Value)).personInfo =
                    applyPersonalInfoPacket.NewPersonalInfo;
                dbc.SubmitChanges();

                return new NetPacket()
                {
                    Tag = PacketTag.ApplyPersonalInfo,
                    Content = new P2PChat.Data.Packets.RawStringPacket()
                    {
                        Content = "SUCCESS",
                    },
                };
            }
            catch (Exception ex)
            {
                return new NetPacket()
                {
                    Tag = PacketTag.ApplyPersonalInfo,
                    Content = new P2PChat.Data.Packets.RawStringPacket()
                    {
                        Content = "更新数据时出现问题!",
                    },
                };
            }
        }

        public static NetPacket AccessRegist(Data.Packets.RegistPacket registPacket)
        {
            DBCDataContext dbc = new DBCDataContext();
            try
            {
                // 判断用户是否已经存在
                if (dbc.tb_Users.Count(x => x.regEmail == registPacket.emailAddress) > 0)
                {
                    // 当用户已经存在,
                    Data.Packets.RegistResultPacket resultPacket = new Data.Packets.RegistResultPacket()
                    {
                        Result = "该电子邮件地址已经被注册!",
                        ResultCode = 1,
                    };
                    return new NetPacket()
                    {
                        Tag = PacketTag.RegistResult,
                        Content = resultPacket,
                    };
                }
                else
                {
                    // 向数据库中添加记录
                    tb_Users newUser = new tb_Users()
                    {
                        regEmail = registPacket.emailAddress,
                        loginPassword = registPacket.password,
                        guid = Guid.NewGuid(),
                        personInfo = new XElement("PersonalInfo"),
                        friendList = new XElement("FriendList",
                            new XElement("Group", new XAttribute("name", "默认分组"))),
                    };
                    dbc.tb_Users.InsertOnSubmit(newUser);
                    dbc.SubmitChanges();

                    return new NetPacket()
                    {
                        Tag = PacketTag.RegistResult,
                        Content = new P2PChat.Data.Packets.RegistResultPacket()
                        {
                            ResultCode = 0,
                            Result = "注册成功!",
                        }
                    };
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 处理登录行为
        /// </summary>
        /// <param name="loginPacket"></param>
        /// <returns></returns>
        public static NetPacket AccessLogin(Data.Packets.LoginPacket loginPacket, IPAddress clientIp)
        {
            DBCDataContext dbc = new DBCDataContext();
            try
            {
                tb_Users user;
                if (dbc.tb_Users.Count(x => x.regEmail == loginPacket.emailAddress) > 0)
                {
                    user = dbc.tb_Users.First(x => x.regEmail == loginPacket.emailAddress);
                    if (user.loginPassword != loginPacket.password)
                    {
                        return new NetPacket()
                        {
                            Tag = PacketTag.LoginResult,
                            Content = new P2PChat.Data.Packets.LoginResultPacket()
                            {
                                ResultCode = 2,
                                Result = "密码错误!",
                            },
                        };
                    }
                    else
                    { // 向节点列表中发送数据
                        ClientList.Clients[user.guid] = new IPEndPoint(clientIp, loginPacket.listeningPort);
                        ClientList.OnlineStatus[user.guid] = "online";

                        // 从user中提取用户的信息并返回给用户
                        XElement personalInfo = new XElement(
                            // 用户信息XML
                            "PersonalInfo",
                            new XAttribute("GUID", user.guid.ToString()),
                            new XAttribute("RegEmail", user.regEmail),
                            user.personInfo.Elements());

                        // 设置好友列表, 添加在线信息
                        XElement friendList = user.friendList;
                        List<Guid> onlineFriends = new List<Guid>();
                        if (friendList.Elements("Group").Count() != 0)
                        {
                            foreach (XElement friend in friendList.Elements("Group").Elements("Friend"))
                            {
                                if (ClientList.OnlineStatus.ContainsKey(Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)))
                                {
                                    if (friend.Element("State") != null)
                                    {
                                        friend.Element("State").Value = 
                                            ClientList.OnlineStatus[Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)].ToLower();
                                    }
                                    else
                                    {
                                        friend.Add(new XElement("State", 
                                            ClientList.OnlineStatus[Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)].ToLower()));
                                    }
                                    onlineFriends.Add(Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value));
                                }
                                else
                                {
                                    // 在线列表中不存在,说明一定是离线
                                    if (friend.Element("State") != null)
                                    {
                                        friend.Element("State").Value = "offline";
                                    }
                                    else
                                    {
                                        friend.Add(new XElement("State", "offline"));
                                    }
                                }

                                // 添加节点信息
                                if (friend.Element("State").Value != "offline")
                                {
                                    if (ClientList.Clients.ContainsKey(
                                        Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)))
                                    {
                                        IPEndPoint ipEndPoint = ClientList.Clients[
                                            Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)];
                                        if (friend.Element("IPEndPoint") != null)
                                        {
                                            friend.Element("IPEndPoint").Remove();
                                        }
                                        XElement ipEndPointXml = new XElement("IPEndPoint", 
                                            new XElement("IPAddress", ipEndPoint.Address.ToString()),
                                            new XElement("Port", ipEndPoint.Port));
                                        friend.Add(ipEndPoint);
                                    }
                                }
                            }


                        }

                        // 向好友发送"好友在线"的消息
                        foreach (Guid friend in onlineFriends)
                        {
                            if (ClientList.OnlineStatus[friend] != "offline")
                            {
                                if (ClientList.Clients.ContainsKey(friend))
                                {
                                    NetPacket friends_packet = new NetPacket()
                                    {
                                        Tag = PacketTag.Notify_OnlineState,
                                        Content = new P2PChat.Data.Packets.Notiry_OnlineState()
                                        {
                                            UserId = user.guid,
                                            OnlineState = ClientList.OnlineStatus[friend],
                                        }
                                    };
                                    MemoryStream ms = new MemoryStream();
                                    BinaryFormatter bf = new BinaryFormatter();
                                    bf.Serialize(ms, friends_packet);

                                    using (TcpClient c = new TcpClient())
                                    {
                                        try
                                        {
                                            c.Connect(ClientList.Clients[friend]);
                                            c.Client.Send(ms.GetBuffer());
                                            c.Close();
                                        }
                                        catch (Exception ex)
                                        {
                                            
                                        }
                                    }
                                }
                            }
                        }

                        Data.Packets.LoginResultPacket resultPacket = new Data.Packets.LoginResultPacket()
                        {
                            Result = "登陆成功!",
                            ResultCode = 0,
                            personalInfo = personalInfo,
                            friendList = friendList
                        };

                        NetPacket packet = new NetPacket()
                        {
                            Content = resultPacket,
                            Tag = PacketTag.LoginResult,
                        };
                        return packet;
                    }


                }
                else // 用户不存在!
                {
                    Data.Packets.LoginResultPacket resultPacket = new Data.Packets.LoginResultPacket()
                    {
                        Result = "用户不存在!",
                        ResultCode = 1,
                    };

                    NetPacket packet = new NetPacket()
                    {
                        Content = resultPacket,
                        Tag = PacketTag.LoginResult,
                    };
                    return packet;
                }
            }
            catch (Exception ex)
            {
                if (iLog != null)
                {
                    iLog.Add(ex.Message);
                }
                throw ex;
            }
        }

        public static P2PChat.Log.ILog iLog = null;

        internal static NetPacket AccessApplyAddFriend(P2PChat.Data.Packets.ApplyAddFriendPacket p)
        {
            DBCDataContext dbc = new DBCDataContext();
            try
            {
                if (dbc.tb_Users.Count(x => x.regEmail == p.FriendEmail) > 0)
                {
                    tb_Users nwFriend = dbc.tb_Users.First(x => x.regEmail == p.FriendEmail),
                        user = dbc.tb_Users.First(x => x.guid == p.UserId);
                    XElement xml = user.friendList;

                    // 检查是否已经是好友了
                    if (xml.Elements("Group").Elements("Friend").Count(
                        x => x.Element("PersonalInfo").Attribute("RegEmail").Value == p.FriendEmail) > 0)
                    {
                        return new NetPacket()
                        {
                            Tag = PacketTag.ApplyAddFriend,
                            Content = new P2PChat.Data.Packets.ApplyAddFriendResultPacketcs()
                            {
                                ResultString = "该用户已经是你的好友了!",
                            },
                        };
                    }

                    // 添加好友
                    if (xml.Elements("Group").Count(x => x.Attribute("name").Value == "默认分组") == 0)
                    {
                        xml.Add(new XElement("Group", new XAttribute("name", "默认分组")));
                    }
                    xml.Elements("Group").First(x => x.Attribute("name").Value == "默认分组").Add(
                        new XElement("Friend", nwFriend.personInfo));
                    dbc.tb_Users.First(x => x.guid == p.UserId).friendList = new XElement(xml);
                    dbc.SubmitChanges();

                    // 重新添加在线信息
                    if (xml.Elements("Group").Count() != 0)
                    {
                        foreach (XElement friend in xml.Elements("Group").Elements("Friend"))
                        {
                            if (ClientList.OnlineStatus.ContainsKey(Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)))
                            {
                                if (friend.Element("State") != null)
                                {
                                    friend.Element("State").Value = ClientList.OnlineStatus[Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)].ToLower();
                                }
                                else
                                {
                                    friend.Add(new XElement("State", ClientList.OnlineStatus[Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)].ToLower()));
                                }
                            }
                            else
                            {
                                // 在线列表中不存在,说明一定是离线
                                if (friend.Element("State") != null)
                                {
                                    friend.Element("State").Value = "offline";
                                }
                                else
                                {
                                    friend.Add(new XElement("State", "offline"));
                                }
                            }

                                // 添加节点信息
                                if (friend.Element("State").Value != "offline")
                                {
                                    if (ClientList.Clients.ContainsKey(
                                        Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)))
                                    {
                                        IPEndPoint ipEndPoint = ClientList.Clients[
                                            Guid.Parse(friend.Element("PersonalInfo").Attribute("GUID").Value)];
                                        if (friend.Element("IPEndPoint") != null)
                                        {
                                            friend.Element("IPEndPoint").Remove();
                                        }
                                        XElement ipEndPointXml = new XElement("IPEndPoint", 
                                            new XElement("IPAddress", ipEndPoint.Address.ToString()),
                                            new XElement("Port", ipEndPoint.Port));
                                        friend.Add(ipEndPoint);
                                    }
                                }
                        }


                    }

                    return new NetPacket()
                    {
                        Tag = PacketTag.ApplyAddFriend,
                        Content = new P2PChat.Data.Packets.ApplyAddFriendResultPacketcs()
                        {
                            ResultString = "SUCCESS",
                            NewFriendList = xml,
                        },
                    };
                }
                else
                {
                    return new NetPacket()
                    {
                        Tag = PacketTag.ApplyAddFriend,
                        Content = new P2PChat.Data.Packets.ApplyAddFriendResultPacketcs()
                        {
                            ResultString = "找不到目标好友数据!",
                        },
                    };
                }
            }
            catch (Exception ex)
            {
                if (iLog != null)
                {
                    iLog.Add("处理添加好友行为时出现异常!");
                }
                throw ex;
            }
        }

        internal static NetPacket AccessGetUserIP(Data.Packets.GetUserIPEndPointPacket getUserIPEndPointPacket)
        {
            string ip = "";
            int port = -1;
            if (ClientList.Clients.ContainsKey(getUserIPEndPointPacket.RemoteUserId))
            {
                ip = ClientList.Clients[getUserIPEndPointPacket.RemoteUserId].Address.ToString();
                port = ClientList.Clients[getUserIPEndPointPacket.RemoteUserId].Port;
            }
            else
            {
                throw new Exception("用户未在线");
            }
            return new NetPacket()
            {
                Tag = PacketTag.GetValue,
                Content = new Data.Packets.GetUserIPEndPointPacket()
                {
                    RemoteUserId = getUserIPEndPointPacket.RemoteUserId,
                    IPAddress = ip,
                    Port = port,
                },
            };
        }
    }
}
